﻿#region using statements

using System;
using System.Collections.Generic;
using XNAGameEngine.Logs;

#endregion

namespace XNAGameEngine.GameObject
{
    /// <summary>
    /// <para>Registry to store all of the registered game object types.</para>
    /// <para>You should have no reason to create one of these in your game</para>
    /// </summary>
    internal sealed class ManagerGameObject2DRegistry
    {
        #region local fields

        /// <summary>
        /// maps a string to a specific GameObject2D type
        /// </summary>
        private readonly Dictionary<string, Type> _registry;

        /// <summary>
        /// reference to the manager containing this object
        /// </summary>
        private ManagerGameObject2D _gameObjectsManager;

        #endregion

        #region constructors

        /// <summary>
        /// Create a new ManagerGameObject2DRegistry
        /// </summary>
        /// <param name="gameObjectsManager">the ManagerGameObjects2D that contains this registry</param>
        public ManagerGameObject2DRegistry(
            ManagerGameObject2D gameObjectsManager)
        {
            _gameObjectsManager = gameObjectsManager;
            _registry = new Dictionary<string, Type>();
            ManagerLogs.Write("ManagerGameObject2DRegistry : Created");
        }

        #endregion

        #region local methods

        /// <summary>
        /// <para>Register a GameObject2D with the registry</para>
        /// <para>IMPORTANT NOTICE: YOU MAY NOT ADD PARAMETERS TO THE CONSTRUCTORS</para>
        /// </summary>
        /// <param name="objectType">the type to register</param>
        public void RegisterGameObject(string key, Type objectType)
        {
            if (!objectType.IsSubclassOf(typeof(GameObject2D)))
                throw new Exception(
                    "Cannot register this type. Type passed in does not inherit GameObject2D");

            if (_registry.ContainsValue(objectType))
                throw new Exception(
                    "This type of object has already been registered");

            if (_registry.ContainsKey(key))
                throw new Exception(
                    "The value " + key + " has already been registered");

            _registry.Add(key, objectType);
        }

        /// <summary>
        /// <para>Register a new game object in the registry.</para>
        /// <para>By default, objects are set as ACTIVE</para>
        /// </summary>
        /// <param name="newObjectKey">
        /// <para>The key value of the object to create</para>
        /// <para>It MUST inherit the base GameObject2D class or an exception will be thrown.</para>
        /// </param>
        /// <param name="objectID">the unique id number of the object being created</param>
        /// <returns>the newly created object</returns>
        public GameObject2D CreateObjectInstance(
            string newObjectKey, int objectID)
        {
            if (!_registry.ContainsKey(newObjectKey))
                throw new SystemException(
                    "The value " + newObjectKey + " has not been registered");

            object[] paramList = new object[1];
            paramList[0] = objectID;

            //grab the object from the registry, get the constructor that corresponds to the parameter type
            //in the array and invoke the constructor with the array of parameters passed in.
            return
                (GameObject2D)
                _registry[newObjectKey].GetConstructors()[0].Invoke(paramList);
        }

        #endregion
    }
}